#include<iostream>
#include<vector>
#include<unordered_map>
#include<algorithm>
#include<map>
#include<set>
#include<unordered_set>
#include<bits/stdc++.h>
#define fi first
#define se second
#define SIZE(x) ((int)x.size())
#define out(x) cerr<<#x<<" = "<<(x)<<endl;
#define MP(a,b) make_pair(a,b)
using namespace std;
typedef long long ll;
#define VI vector<int>
#define VVI vector< vector<int> >
#define VC vector<char>
#define PI pair<int,int>
#define PL pair<ll,ll>
#define EPS 0.0000001


inline int lson(int x){return x<<1;}
inline int rson(int x){return (x<<1)|1;}

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
	while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}

template<typename T> 
inline void read(T &x){
	x=0;T f=1;char ch;
	do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
	do x=x*10+ch-'0',ch=getchar();while(ch<='9'&&ch>='0');x*=f;
}
const int maxn=100005;
struct {
	int to,ne;
}e[200005];
int esum=0;
int head[maxn];
void edgadd(int x,int y){ //x->y
	++esum;
	e[esum].ne=head[x];
	e[esum].to=y;
	head[x]=esum;
}

//结点个数，操作数，根节点序号，取模数
ll n,m,r,p;
//节点val
ll val[maxn];
//子树大小
int chs[maxn];
//节点深度
int dep[maxn];
//父亲
int fa[maxn];
//重儿子编号
int son[maxn];
//处理出来上述所有数组
void dfs1(int r,int f,int d){
	dep[r]=d++;
	fa[r]=f;
	int tmp;
	chs[r]+=1;
	int hs=0;
	for(int i=head[r];i;i=e[i].ne){
		tmp=e[i].to;
		if(tmp==f)continue;
		dfs1(tmp,r,d);
		chs[r]+=chs[tmp];
		if(!hs||chs[tmp]>chs[hs])hs=tmp;
	}
	son[r]=hs;
}
//节点新编号
int id[maxn];
//节点顶端
int top[maxn];
//节点数值转移
ll nval[maxn];
int cnt=0;
//处理新编号，赋值到新编号，处理顶端节点
void dfs2(int r,int t){
	id[r]=++cnt;
	nval[cnt]=val[r];
	top[r]=t;
	if(!son[r])return ;
	dfs2(son[r],t);
	int tmp;
	for(int i=head[r];i;i=e[i].ne){
		tmp=e[i].to;
		if(tmp==fa[r]||tmp==son[r])continue;
		dfs2(tmp,tmp);
	}
}
//线段树模式
ll tr[4*maxn];
ll tag[4*maxn];
void pushup(int a,int b,int x){
	if(a==b)return;
	tr[x]=tr[lson(x)]+tr[rson(x)];
	tr[x]%=p;
}
void pushdown(int a,int b,int x){
	if(a==b)return;
	int mid=(a+b)/2;
	int tmp=tag[x];
	tag[x]=0;
	tag[lson(x)]+=tmp;
	tag[lson(x)]%=p;
	tag[rson(x)]+=tmp;
	tag[rson(x)]%=p;
	tr[lson(x)]+=tmp*(mid-a+1);
	tr[lson(x)]%=p;
	tr[rson(x)]+=tmp*(b-mid);
	tr[rson(x)]%=p;
}
void build(int a,int b,int x){//构建线段树
	if(a==b){
		tr[x]=nval[a];
		return;
	}
	int mid=(a+b)/2;
	build(a,mid,lson(x));
	build(mid+1,b,rson(x));
	pushup(a,b,x);
}
void upd(int l,int r,int a,int b,int x,int v){
	if(a>=l&&b<=r){
		tr[x]+=v*(b-a+1);
		tr[x]%=p;
		tag[x]+=v;
		tag[x]%=p;
		return;
	}
	pushdown(a,b,x);
	int mid=(a+b)/2;
	if(l<=mid)upd(l,r,a,mid,lson(x),v);
	if(r>mid)upd(l,r,mid+1,b,rson(x),v);
	pushup(a,b,x);
}
ll que(int l,int r,int a,int b,int x){
	if(a>=l&&b<=r){
		return tr[x];
	}
	pushdown(a,b,x);
	int mid=(a+b)/2;
	ll res=0;
	if(l<=mid)res=(res+que(l,r,a,mid,lson(x)))%p;
	if(r>mid)res=(res+que(l,r,mid+1,b,rson(x)))%p;
	return res;
}
//更新x到y路径上的节点值
void updrange(int x,int y,int k){
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]])swap(x,y);
		upd(id[top[x]],id[x],1,cnt,1,k);
		x=fa[top[x]];
	}
	if(dep[x]>dep[y])swap(x,y);
	upd(id[x],id[y],1,cnt,1,k);
}
//获取路径和
ll queRange(int x,int y){
	ll ans=0;
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]])swap(x,y);
		ans+=que(id[top[x]],id[x],1,cnt,1);
		ans%=p;
		x=fa[top[x]];
	}
	if(dep[x]>dep[y])swap(x,y);
	ans+=que(id[x],id[y],1,cnt,1);
	ans%=p;
	if(ans<0){cout<<"shit";exit(-1);};
	return ans;
}
//更新子树
void updSon(int x,int k){
	upd(id[x],id[x]+chs[x]-1,1,cnt,1,k);
}
//获取子树和
ll queSon(int x){
	return que(id[x],id[x]+chs[x]-1,1,cnt,1);
}
//3384轻重链剖分
int main(){
    #ifdef BUG
    freopen("a.in","r",stdin);
    #endif
	n=read();m=read();r=read();p=read();
	for(int i=1;i<=n;i++)val[i]=read()%p;
	memset(head,0,sizeof head);
	memset(chs,0,sizeof chs);
	memset(tag,0,sizeof tag);
	int a,b;
	for(int i=1;i<n;i++){
		a=read();b=read();
		edgadd(a,b);
		edgadd(b,a);
	}
	dfs1(r,0,1);
	dfs2(r,r);
	build(1,cnt,1);
	int x,y,z;
	while(m--){
		a=read();
		if(a==1){
			x=read();y=read();z=read()%p;
			updrange(x,y,z);
		}else if(a==2){
			x=read();y=read();
			printf("%d\n",queRange(x,y));
		}else if(a==3){
			x=read();z=read()%p;
			updSon(x,z);
		}else if(a==4){
			x=read();
			printf("%d\n",queSon(x));
		}
	}
}

